home *** CD-ROM | disk | FTP | other *** search
- //
- // This is a patch for the Inventor 2.0 Text3 node, which will
- // core dump when given an character code in the range 128-255.
- //
- // To apply this patch, compile this file into a .o and then link
- // the .o before -lInventor. You will also need to link with -lFL,
- // the internal, undocumented font library that Inventor uses (sorry,
- // no, a public, released, documented version is NOT available).
- // The linker may give a warning about
- // multiply defined symbols. This is normal and expected.
- //
-
- #include <Inventor/caches/SoGLRenderCache.h>
- #include <Inventor/elements/SoCacheElement.h>
- #include <Inventor/elements/SoComplexityElement.h>
- #include <Inventor/elements/SoComplexityTypeElement.h>
- #include <Inventor/elements/SoCreaseAngleElement.h>
- #include <Inventor/elements/SoFontNameElement.h>
- #include <Inventor/elements/SoFontSizeElement.h>
- #include <Inventor/elements/SoGLCacheContextElement.h>
- #include <Inventor/elements/SoGLTextureCoordinateElement.h>
- #include <Inventor/elements/SoGLTextureEnabledElement.h>
- #include <Inventor/elements/SoMaterialBindingElement.h>
- #include <Inventor/elements/SoModelMatrixElement.h>
- #include <Inventor/elements/SoProfileElement.h>
- #include <Inventor/elements/SoProfileCoordinateElement.h>
- #include <Inventor/elements/SoProjectionMatrixElement.h>
- #include <Inventor/elements/SoViewportRegionElement.h>
- #include <Inventor/elements/SoViewingMatrixElement.h>
- #include <Inventor/errors/SoDebugError.h>
- #include <Inventor/misc/SoState.h>
- #include <Inventor/nodes/SoText3.h>
- #include <Inventor/nodes/SoProfile.h>
-
- #include <GL/gl.h>
-
- // Internal font library stuff from the unshipped flclient.h.
- // DO NOT TRY TO USE THIS!
- class SoFontOutline;
- typedef GLint FLfontNumber;
- typedef struct __FLcontextRec *FLcontext;
- #define FL_HINT_AABITMAPFONTS 1 /* bound to font */
- #define FL_HINT_CHARSPACING 2 /* bound to font */
- #define FL_HINT_FONTTYPE 3 /* bound to font */
- #define FL_HINT_MAXAASIZE 4 /* bound to font */
- #define FL_HINT_MINOUTLINESIZE 5 /* bound to font */
- #define FL_HINT_ROUNDADVANCE 6 /* bound to font */
- #define FL_HINT_SCALETHRESH 7 /* bound to font */
- #define FL_HINT_TOLERANCE 8 /* bound to font */
-
- extern "C" {
-
- FLfontNumber flCreateFont(
- const GLubyte * /* fontName */,
- GLfloat [2][2] /* mat */,
- GLint /* charNameCount */,
- GLubyte ** /* charNameVector */
- );
- void flSetHint(
- GLuint /* hint */,
- GLfloat /* hintValue */
- );
- GLboolean flMakeCurrentFont(
- FLfontNumber /* fn */
- );
- };
-
- //
- // Internal class: SoOutlineFontCache
- //
-
- // Callback function for sides of characters-- passed the number of
- // points going back, and points and normals on either edge of the
- // strip. tTexCoords[0] and [1] are for the two edges, and the
- // sTexCoords are the same for both edges.
- typedef void SideCB(int nPoints,
- const SbVec3f *points1, const SbVec3f *norms1,
- const SbVec3f *points2, const SbVec3f *norms2,
- const float *sTexCoords, const float *tTexCoords);
-
- // This is pretty heavyweight-- it is responsible for doing all of the
- // grunt work of figuring out the polygons making up the characters in
- // the font.
- class SoOutlineFontCache : public SoGLRenderCache
- {
- public:
- // Given a state, find an appropriate outline font.
- static SoOutlineFontCache *getFont(SoState *, SbBool forRender);
-
- // Checks to see if this font is valid
- SbBool isValid(SoState *state) const;
-
- // Figures out if this cache is valid for rendering (the base
- // class isValid can be used for all other actions)
- SbBool isRenderValid(SoState *state) const;
-
- // Returns the width of given string
- float getWidth(const SbString &string);
-
- // Returns height of font
- float getHeight() { return fontSize; }
-
- // Returns the 2D bounding box of a character
- void getCharBBox(const char c, SbBox2f &result);
- // ... and the bounding box of the font's bevel
- void getProfileBBox(SbBox2f &result);
-
- // Return the first/last point in the profile:
- void getProfileBounds(float &firstZ, float &lastZ);
-
- // Returns TRUE if there _is_ any profile
- // (if not, act as if SIDES of text are off)
- SbBool hasProfile() const { return (nProfileVerts > 1); }
-
- // Returns how far to advance after drawing given character:
- SbVec2f getCharOffset(const char c);
-
- // Uses the given glu tesselator to generate triangles for the
- // given character. This is used for both rendering and
- // generating primitives, with just different callback routines
- // registered.
- void generateFrontChar(const char c, GLUtriangulatorObj *tobj);
- // Ditto, for sides of characters:
- void generateSideChar(const char c, SideCB callbackFunc);
-
- // Set up for GL rendering:
- void setupToRenderFront(SoState *state);
- void setupToRenderSide(SoState *state);
-
- // Returns TRUE if this font cache has a display list for the
- // given character. It will try to build a display list, if it
- // can.
- SbBool hasFrontDisplayList(const char c, GLUtriangulatorObj *tobj);
- SbBool hasSideDisplayList(const char c, SideCB callbackFunc);
-
- // Renders an entire string by using the GL callList() function.
- void callFrontLists(const SbString &string);
- void callSideLists(const SbString &string);
-
- // Renders a string in cases where display lists can't be buit.
- void renderFront(const SbString &string,
- GLUtriangulatorObj *tobj);
- void renderSide(const SbString &string,
- SideCB callbackFunc);
-
- // Callback registered with GLU used to detect tesselation errors.
- static void errorCB(GLenum whichErr);
-
- protected:
-
- // Free up display lists before being deleted
- virtual void destroy(SoState *state);
-
- private:
- // Constructor
- SoOutlineFontCache(SoState *);
- // Destructor
- ~SoOutlineFontCache();
-
- // Return a convnient little class representing a character's
- // outline.
- SoFontOutline *getOutline(const char c);
-
- // Some helper routines for generateSide:
- void figureSegmentNorms(SbVec2f *result, int nPoints,
- const SbVec2f *points, float cosCreaseAngle, SbBool isClosed);
- void figureSegmentTexCoords(float *texCoords, int nPoints,
- const SbVec2f *points, SbBool isClosed);
- void fillBevel(SbVec3f *result, int nPoints,
- const SbVec2f *points, const SbVec2f &translation,
- const SbVec2f &n1, const SbVec2f &n2);
- void fillBevelN(SbVec3f *result, int nPoints,
- const SbVec2f *norms, const SbVec2f &n);
-
- // Cache context
- int cacheContext;
-
- // Number of characters in this font. Until we internationalize,
- // this will be 256 or less.
- int numChars;
-
- // Starting index of blocks of display lists for front/sides:
- GLuint frontListBase;
- GLuint sideListBase;
-
- // Profile information:
- float cosCreaseAngle;
- long nProfileVerts; // Number of points in profile
- SbVec2f *profileVerts; // Profile vertices
- float *sTexCoords; // Texture coordinates along profile
- // (nProfileVerts of them)
- SbVec2f *profileNorms; // Profile normals
- // ((nProfileVerts-1)*2 of them)
-
- // This flag will be true if there is another cache open (if
- // building GL display lists for render caching, that means we
- // can't also build display lists).
- SbBool otherOpen;
-
- // And tables telling us if a display list has been created for
- // each character in the font (we do that lazily since it is
- // expensive):
- SbBool *frontFlags;
- SbBool *sideFlags;
-
- // List of outlines; these are also cached and created when
- // needed.
- SoFontOutline **outlines;
-
- // Font size
- float fontSize;
-
- // Flag used to detect tesselation errors:
- static SbBool tesselationError;
-
- // Font library identifier for this font
- FLfontNumber fontId;
-
- // Font library context for all outline fonts
- static FLcontext context;
-
- // Global list of available fonts; a 'font' in this case is a
- // unique set of font name, font size, complexity value/type, and
- // set of profiles-- if any of these changes, the set of polygons
- // representing the font will change, and a different font will be
- // used.
- static SbPList *fonts;
- };
-
-
- ////////////////////////////////////////////////////////////////////////
- //
- // Description:
- // Constructor. Called by getFont().
- //
- // Use: private
-
- SoOutlineFontCache::SoOutlineFontCache(SoState *state) :
- SoGLRenderCache(state)
- //
- ////////////////////////////////////////////////////////////////////////
- {
- ref();
-
- // Tell base class to ignore overridden elements in isValid
- // check-- this is safe because the only relevant elements are
- // guaranteed to already be on the elementsUsed list, so we're
- // sure to detect changes to them.
- setCompareOverridden(FALSE);
-
- cacheContext = -1;
-
- // Add element dependencies explicitly here; making 'this' the
- // CacheElement doesn't work if we are being constructed in an
- // action that doesn't have caches.
- SbName font = SoFontNameElement::get(state);
- addElement(state->getConstElement(
- SoFontNameElement::getClassStackIndex()));
- if (font == SoFontNameElement::getDefault()) {
- font = SbName("Utopia-Regular");
- }
-
- float uems;
-
- // Remember size
- fontSize = SoFontSizeElement::get(state);
- addElement(state->getConstElement(
- SoFontSizeElement::getClassStackIndex()));
-
- // Figure out complexity...
- float complexity = SoComplexityElement::get(state);
- addElement(state->getConstElement(
- SoComplexityElement::getClassStackIndex()));
- addElement(state->getConstElement(
- SoComplexityTypeElement::getClassStackIndex()));
-
- switch (SoComplexityTypeElement::get(state)) {
- case SoComplexityTypeElement::OBJECT_SPACE:
- {
- // Two ramps-- complexity of zero == 250/1000 of an em
- // complexity of .5 == 20/1000 of an em
- // complexity of 1 == 1/1000 of an em
- const float ZERO = 250;
- const float HALF = 20;
- const float ONE = 1;
- if (complexity > 0.5) uems = (2.0-complexity*2.0)*(HALF-ONE)+ONE;
- else uems = (1.0-complexity*2.0)*(ZERO-HALF)+HALF;
- }
- break;
-
- case SoComplexityTypeElement::SCREEN_SPACE:
- {
- SbVec3f p(fontSize, fontSize, fontSize);
- SbVec2s rectSize;
-
- SoShape::getScreenSize(state, SbBox3f(-p, p), rectSize);
- float maxSize =
- (rectSize[0] > rectSize[1] ? rectSize[0] : rectSize[1]);
- uems = 250.0 / (1.0 + 0.25 * maxSize * complexity *
- complexity);
-
- // We have to manually add the dependency on the
- // projection, view and model matrix elements (these are
- // gotten in the SoShape::getScreenSize routine), and the
- // ViewportRegionElement:
- addElement(state->getConstElement(
- SoProjectionMatrixElement::getClassStackIndex()));
- addElement(state->getConstElement(
- SoViewingMatrixElement::getClassStackIndex()));
- addElement(state->getConstElement(
- SoModelMatrixElement::getClassStackIndex()));
- addElement(state->getConstElement(
- SoViewportRegionElement::getClassStackIndex()));
- }
- break;
-
- case SoComplexityTypeElement::BOUNDING_BOX:
- {
- uems = 20;
- }
- break;
- }
- flSetHint(FL_HINT_TOLERANCE, uems);
-
- static GLfloat m[2][2] = { 1.0, 0.0, 0.0, 1.0 };
-
- fontId = flCreateFont((const GLubyte *)font.getString(), m, 0, NULL);
-
- // If error creating font:
- if (fontId == 0) {
- // Try Utopia-Regular, unless we just did!
- if (font != SbName("Utopia-Regular")) {
- #ifdef DEBUG
- SoDebugError::post("SoText3::getFont",
- "Couldn't find font %s, replacing with Utopia-Regular",
- font.getString());
- #endif
- fontId = flCreateFont((GLubyte *)"Utopia-Regular", m, 0, NULL);
- }
- if (fontId == 0) {
- #ifdef DEBUG
- SoDebugError::post("SoText3::getFont",
- "Couldn't find font Utopia-Regular!");
- #endif
- return;
- }
- }
-
- flMakeCurrentFont(fontId);
-
- numChars = 256; // ??? NEED TO REALLY KNOW HOW MANY CHARACTERS IN
- // FONT!
- frontListBase = 0;
- sideListBase = 0;
-
- frontFlags = new SbBool[numChars];
- sideFlags = new SbBool[numChars];
- outlines = new SoFontOutline*[numChars];
- for (int i = 0; i < numChars; i++) {
- frontFlags[i] = sideFlags[i] = FALSE;
- outlines[i] = NULL;
- }
-
- // Get profile info:
- const SoNodeList &profiles = SoProfileElement::get(state);
- addElement(state->getConstElement(
- SoProfileElement::getClassStackIndex()));
- addElement(state->getConstElement(
- SoProfileCoordinateElement::getClassStackIndex()));
- nProfileVerts = 0;
- if (profiles.getLength() > 0) {
- SoProfile *profileNode = (SoProfile *)profiles[0];
- profileNode->getVertices(state, nProfileVerts, profileVerts);
- } else {
- nProfileVerts = 2;
- profileVerts = new SbVec2f[2];
- profileVerts[0].setValue(0, 0);
- profileVerts[1].setValue(1, 0);
- }
-
- if (nProfileVerts > 1) {
- cosCreaseAngle = cos(SoCreaseAngleElement::get(state));
- addElement(state->getConstElement(
- SoCreaseAngleElement::getClassStackIndex()));
- int nSegments = (int) nProfileVerts - 1;
-
- // Figure out normals for profiles; there are twice as many
- // normals as segments. The two normals for each segment endpoint
- // may be averaged with the normal for the next segment, depending
- // on whether or not the angle between the segments is greater
- // than the creaseAngle.
- profileNorms = new SbVec2f[nSegments*2];
- figureSegmentNorms(profileNorms, (int) nProfileVerts, profileVerts,
- cosCreaseAngle, FALSE);
- // Need to flip all the normals because of the way the profiles
- // are defined:
- for (i = 0; i < nSegments*2; i++) {
- profileNorms[i] *= -1.0;
- }
-
- // Figure out S texture coordinates, which run along the profile:
- sTexCoords = new float[nProfileVerts];
- figureSegmentTexCoords(sTexCoords, (int) nProfileVerts,
- profileVerts, FALSE);
- // And reverse them, so 0 is at the back of the profile:
- float max = sTexCoords[nProfileVerts-1];
- for (i = 0; i < nProfileVerts; i++) {
- sTexCoords[i] = max - sTexCoords[i];
- }
- } else {
- profileNorms = NULL;
- sTexCoords = NULL;
- }
-
- fonts->append(this);
- }
-
-